﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using FXC.SL.Interface;
using FXC.SL.CS.Util;
using Visifire.Charts;
using FXC.SL.UserControls.Window;
using FXC.SL.FXCenterService;
using System.IO;
using System.Windows.Media.Imaging;
using FXC.SL.CS.ChartUtil;

namespace FXC.SL.UserControls.FXCChart
{
    public partial class FXVChart : UserControl, IChart
    {
        private string _productName;
        private int _yAxisMinWidth = 40;
        private PeriodType _periodType = PeriodType.T_1D;
        private PlotArea chartArea = new PlotArea();
        private ChartType _chartType = ChartType.CandleStick;
        DataSeries dataSeries = new DataSeries();
        private int _zoom = 1;
        private ChartTheme _chartTheme = new ChartTheme();
        int MouseStatus = 0;
        Point clickPoint;
        int tag = 0;
        List<FXCenterService.FXData> _source;
        bool _isIndicatorEnabled = true;

        FXCenterService.FXCServiceClient proxy = FXCServiceClientManager.CreateProxy();

        SaveFileDialog _saveImgFileDialgue = new SaveFileDialog();

        public FXVChart(string ProductCode, PeriodType periodType)
        {
            InitializeComponent();
            _productName = ProductCode;
            _periodType = periodType;
            InitialMainChartArea();
            InitialVolumeChartArea();
            GetDataFromService();
            InitialSeries();
            rcProduct.IndicatorEnabled = true;
            rcVolume.IndicatorEnabled = true;
            rcProduct.AxesX[0].Scroll += new EventHandler<AxisScrollEventArgs>(FXVChart_Scroll);
            rcProduct.PlotArea.MouseMove += new EventHandler<PlotAreaMouseEventArgs>(rcProductPlotArea_MouseMove);
            rcProduct.PlotArea.MouseLeave += new EventHandler<MouseEventArgs>(rcProductPlotArea_MouseLeave);
            rcVolume.PlotArea.MouseMove += new EventHandler<PlotAreaMouseEventArgs>(rcVolumePlotArea_MouseMove);
            rcVolume.PlotArea.MouseLeave += new EventHandler<MouseEventArgs>(rcVolumePlotArea_MouseLeave);

            //rcProduct.AxesY[0].MouseLeave += new EventHandler<MouseEventArgs>(FXVChart_MouseLeave);
            //rcProduct.AxesY[0].MouseEnter += new EventHandler<MouseEventArgs>(FXVChart_MouseEnter);
            //rcProduct.ZoomingEnabled = true;
        }

        void rcProductPlotArea_MouseLeave(object sender, MouseEventArgs e)
        {
            rcVolume.HideIndicator();
        }

        void rcProductPlotArea_MouseMove(object sender, PlotAreaMouseEventArgs e)
        {
            int i = System.Convert.ToInt32(e.XValue)-1;
            if (_source== null || _source.Count <= 0 )
                return;
            
            if (i >=0 && i < _source.Count)
            {
                FXData data = _source[i];
                if (OnMouseMove != null)
                {
                    OnMouseMove(this, new ChartMouseMoveEventArgs() { CurrentData = data });
                }
            }
            rcVolume.ShowIndicator(e.XValue, e.YValue);
        }

        void rcVolumePlotArea_MouseLeave(object sender, MouseEventArgs e)
        {
            rcProduct.HideIndicator();
        }

        void rcVolumePlotArea_MouseMove(object sender, PlotAreaMouseEventArgs e)
        {
            int i = System.Convert.ToInt32(e.XValue) - 1;
            if (_source == null || _source.Count <= 0)
                return;

            if (i >= 0 && i < _source.Count)
            {
                FXData data = _source[i];
                if (OnMouseMove != null)
                {
                    OnMouseMove(this, new ChartMouseMoveEventArgs() { CurrentData = data });
                }
            }
            rcProduct.ShowIndicator(e.XValue, e.YValue);
        }

        void FXVChart_Scroll(object sender, AxisScrollEventArgs e)
        {
            Axis axis = sender as Axis;
            rcVolume.AxesX[0].ScrollBarOffset = axis.ScrollBarOffset;
        }



        private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
        {
 
        }

        #region Private Method
        private void InitialMainChartArea()
        {
            rcProduct.AnimationEnabled = false;
            rcProduct.PlotArea = new PlotArea();
            rcProduct.PlotArea.Background = FXVChartTheme.BackgroundColor;
            rcProduct.PlotArea.Foreground = FXVChartTheme.ForegroundColor;
            Axis axisX = new Axis();
            ChartGrid gridX = new ChartGrid();
            gridX.Interval = 5;
            gridX.Enabled = true;
            gridX.LineColor = FXVChartTheme.GridColor;
            gridX.LineThickness = 0.5;
            axisX.Grids.Add(gridX);

            axisX.ScrollBarScale = 0.3;
            axisX.ScrollBarOffset = 1;
            AxisLabels axisLabels = new AxisLabels();

            axisLabels.Interval = 20;
            //axisLabels.Angle = -30;
            //TODO: axisX Format
            //TODO: ZOOM
            //axisX.AxisLabels.f
            axisX.AxisLabels = axisLabels;
            rcProduct.AxesX.Add(axisX);
            //rcVolume.AxesX.Add(axisX);

            Axis axisY = new Axis();
            //axisY.Width = 30;
            ChartGrid gridY = new ChartGrid();
            gridY.Enabled = true;
            //gridY.Interval = 5;
            gridY.LineColor = FXVChartTheme.GridColor;
            axisY.Grids.Add(gridY);
            axisY.AxisType = AxisTypes.Secondary;
            axisY.ValueFormatString = "0.00#";
            axisY.MinWidth = _yAxisMinWidth;
            axisY.StartFromZero = false;
            //axisY.Interval = 0.002;
            //rcProduct.AxesY.Clear();
            rcProduct.AxesY.Add(axisY);
        }

        private void InitialVolumeChartArea()
        {
            rcVolume.AnimationEnabled = false;
            rcVolume.PlotArea = new PlotArea();

            rcVolume.PlotArea.Background = FXVChartTheme.BackgroundColor;
            rcVolume.PlotArea.Foreground = FXVChartTheme.ForegroundColor;
            Axis axisX = new Axis();
            ChartGrid gridX = new ChartGrid();
            gridX.Interval = 5;
            gridX.Enabled = true;
            gridX.LineThickness = 0.5;
            axisX.Interval = 5;
            //gridX.LineColor = FXVChartTheme.GridColor;
            axisX.Grids.Add(gridX);

            axisX.ScrollBarScale = 0.3;
            axisX.ScrollBarOffset = 1;
            axisX.Enabled = true;
            axisX.ScrollBarSize = 0;
            AxisLabels axisLabels = new AxisLabels();

            axisLabels.FontColor = new SolidColorBrush(Colors.White);
            axisLabels.Interval = 500;
            ////axisLabels.Angle = -30;
            ////TODO: axisX Format
            ////TODO: ZOOM
            ////axisX.AxisLabels.f
            axisX.AxisLabels = axisLabels;
            rcVolume.AxesX.Add(axisX);
            //rcVolume.AxesX.Add(axisX);

            Axis axisY = new Axis();
            //axisY.Width = 30;
            ChartGrid gridY = new ChartGrid();
            gridY.Enabled = true;
            //gridY.Interval = 5;
            //gridY.LineColor = FXVChartTheme.GridColor;
            axisY.Grids.Add(gridY);
            axisY.MinWidth = _yAxisMinWidth;
            axisY.AxisType = AxisTypes.Secondary;
            //axisY.ValueFormatString = "0.0000#";
            //axisY.StartFromZero = false;
            //axisY.Interval = 0.002;
            //rcProduct.AxesY.Clear();
            rcVolume.AxesY.Add(axisY);
        }

        private void GetDataFromService()
        {
            proxy.GetFXCDataCompleted += (o, e) =>
            {
                if (e.Error == null)
                {
                    _source = e.Result.OrderBy(a=>a.ProcessDateTime).ToList();
                    BindData(_source);
                }
                else
                {
                    string msg = e.Error.Message;
                    if(e.Error.InnerException!=null)
                        msg += "Inner Exception:" + e.Error.InnerException.Message;
                    MessageBox.Show(msg);
                }
                fxcLoading.Visibility = System.Windows.Visibility.Collapsed;
            };
            if (fxcLoading.Visibility != System.Windows.Visibility.Visible)
                fxcLoading.Visibility = System.Windows.Visibility.Visible;
            proxy.GetFXCDataAsync(_productName, this.PeriodType.ToString().Substring(2));
        }

        private void BindData(List<FXCenterService.FXData> list)
        {
            if (list != null && list.Count > 0)
            {
                tbMsg.Visibility = System.Windows.Visibility.Collapsed;
                rcVolume.Series[0].DataSource = list;
                dataSeries.DataSource = list;
                rcProduct.Visibility = System.Windows.Visibility.Visible;
                rcVolume.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                rcVolume.Series[0].DataSource = null;
                dataSeries.DataSource = null;
                rcProduct.Visibility = System.Windows.Visibility.Collapsed;
                rcVolume.Visibility = System.Windows.Visibility.Collapsed;
                tbMsg.Visibility = System.Windows.Visibility.Visible;
            }
        }



        private void InitialSeries()
        {
            RebindMainSeries(RenderAs.CandleStick);
            RebindVolumeSeries();
        }

        private void RebindVolumeSeries()
        {
            DataSeries volumeDS = new DataSeries();
            var imVolume = new DataMapping() { MemberName = "YValue", Path = "Volume" };
            var imZDate = new DataMapping() { MemberName = "AxisXLabel", Path = "ProcessDateTime" };

            volumeDS.DataMappings.Add(imVolume);
            volumeDS.DataMappings.Add(imZDate);

            volumeDS.AxisYType = AxisTypes.Secondary;

            rcVolume.Series.Add(volumeDS);
        }

        private void RebindMainSeries(RenderAs renderAs)
        {
            dataSeries.RenderAs = renderAs;

            //DataMapping x = new DataMapping(){ MemberName = "AxisXLabel", Path="ProcessDateTime"};
            var imHigh = new DataMapping(){ MemberName = "High", Path="HighPrice"};
            var imLow = new DataMapping(){ MemberName = "Low", Path="LowPrice"};
            var imOpen = new DataMapping(){ MemberName = "Open", Path="OpenPrice"};
            var imClose = new DataMapping(){ MemberName = "Close", Path="ClosePrice"};
            
            //var imXDate = new ItemMapping("ID", DataPointMember.XValue);
            var imYDate = new DataMapping(){ MemberName = "YValue", Path="ClosePrice"};
            var imZDate = new DataMapping(){ MemberName = "AxisXLabel", Path="ProcessDateTime"};

            dataSeries.DataMappings.Add(imHigh);
            dataSeries.DataMappings.Add(imLow);
            dataSeries.DataMappings.Add(imOpen);
            dataSeries.DataMappings.Add(imClose);
            dataSeries.DataMappings.Add(imYDate);
            dataSeries.DataMappings.Add(imZDate);

            dataSeries.AxisYType = AxisTypes.Secondary;
            dataSeries.PriceUpColor = FXVChartTheme.BarStrokeColor;
            dataSeries.PriceDownColor = FXVChartTheme.BarFillColor;

            rcProduct.Series.Add(dataSeries);


        }
        #endregion

        #region Implement Interface
        public void ChangeZoomBig()
        {
            if (_zoom < 4)
            {
                rcProduct.AxesX[0].ScrollBarScale = rcProduct.AxesX[0].ScrollBarScale - 0.05;
                rcVolume.AxesX[0].ScrollBarScale = rcVolume.AxesX[0].ScrollBarScale - 0.05;
                _zoom++;
            }

            //rcProduct.AxesY[0].SetValue() = (double)rcProduct.AxesY[0].ActualAxisMaximum + 0.005;
            //rcProduct.AxesY[0].Zoom((double)rcProduct.AxesY[0].ActualAxisMinimum + 0.005, (double)rcProduct.AxesY[0].ActualAxisMaximum - 0.005);
        }

        public void ChangeZoomSmall()
        {
            if (_zoom > 0)
            {
                rcProduct.AxesX[0].ScrollBarScale = rcProduct.AxesX[0].ScrollBarScale + 0.05;
                rcVolume.AxesX[0].ScrollBarScale = rcVolume.AxesX[0].ScrollBarScale + 0.05;
                _zoom--;
            }
        }

        public void Refresh()
        {
            GetDataFromService();
        }

        public void ChartPropertySetting()
        {
            ChartProperty formChartProperty = new ChartProperty(this);
            formChartProperty.ShowDialog();
            formChartProperty.Closed += new EventHandler<Telerik.Windows.Controls.WindowClosedEventArgs>(formChartProperty_Closed);
        }

        void formChartProperty_Closed(object sender, Telerik.Windows.Controls.WindowClosedEventArgs e)
        {
            //if (e.DialogResult.HasValue && e.DialogResult.Value)
            //{
            //    BackgroundColor = rcpBackground.SelectedColor;
            //    ForegroundColor = form.rcpForeground.SelectedColor;
            //    GridColor = form.rcpGrid.SelectedColor;
            //    BarStrokeColor = form.rcpBarStroke.SelectedColor;
            //    BarFillColor = form.rcpBarFill.SelectedColor;
            //    VolumeColor = form.rcpVolume.SelectedColor;
            //    LineTypeColor = form.rcpLineType.SelectedColor;
            //}
        }

        public void SaveData()
        {
            List<FXData> lstData = dataSeries.DataSource as List<FXData>;
            if (lstData == null || lstData.Count == 0)
            {
                MessageBox.Show("当前图表没有任何数据可以被导出");
                return;
            }
            _saveImgFileDialgue.DefaultExt = ".csv";
            _saveImgFileDialgue.Filter = "CSV(*.csv)|*.csv";
            _saveImgFileDialgue.FilterIndex = 2;
            bool? dialogResult = _saveImgFileDialgue.ShowDialog();
            if (dialogResult == true)
            {
                System.Text.StringBuilder sbContent = new System.Text.StringBuilder();
                for (int i = 0; i < lstData.Count; i++)
                {
                    sbContent.Append(string.Format("ID={0},OpenPrice={1},ClosePrice={2},HighPrice={3},LowPrice={4},ProcessDateTime={5};", lstData[i].ID, lstData[i].OpenPrice,
                        lstData[i].ClosePrice, lstData[i].HighPrice, lstData[i].LowPrice, lstData[i].ProcessDateTime));
                }
                using (Stream stream = _saveImgFileDialgue.OpenFile())
                {
                    Byte[] fileContent = System.Text.UTF8Encoding.UTF8.GetBytes(sbContent.ToString());
                    stream.Write(fileContent, 0, fileContent.Length);
                    stream.Close();
                }
            }
        }

        public void SaveToImage()
        {
            _saveImgFileDialgue.DefaultExt = ".bmp";
            _saveImgFileDialgue.Filter = "Bitmap(*.bmp)|*.bmp";
            _saveImgFileDialgue.FilterIndex = 2;
            bool? dialogResult = _saveImgFileDialgue.ShowDialog();
            if (dialogResult == true)
            {
                WriteableBitmap btm = new WriteableBitmap((int)gdChartHolder.ActualWidth, (int)gdChartHolder.ActualHeight);
                btm.Render(gdChartHolder, null);
                btm.Invalidate();

                using (Stream stream = _saveImgFileDialgue.OpenFile())
                {
                    byte[] buffer = ImageUtil.GetBuffer(btm);
                    stream.Write(buffer, 0, buffer.Length);
                }
            }
            //rcProduct.Export();
        }

        public event EventHandler<CS.Util.PeriodTypeChangeEventArgs> OnPeriodTypeChanged;

        public event EventHandler<CS.Util.ChartTypeChangeEventArgs> OnChartTypeChanged;

        public event EventHandler OnBackgourdChanged;

        public event EventHandler<CS.Util.IsShowVolumeChangeEventArgs> OnShowVolumeChanged;

        public event EventHandler<CS.Util.ChartMouseMoveEventArgs> OnMouseMove;

        public CS.Util.ChartType ChartType
        {
            get
            {
                return _chartType;
            }
            set
            {
                _chartType = value;
                switch (_chartType)
                {
                    case CS.Util.ChartType.CandleStick:
                        dataSeries.RenderAs = RenderAs.CandleStick;
                        break;
                    case CS.Util.ChartType.Line:
                        dataSeries.RenderAs = RenderAs.Spline;
                        break;
                    case CS.Util.ChartType.Stick:
                        dataSeries.RenderAs = RenderAs.Stock;
                        break;
                }
                if (OnChartTypeChanged != null)
                    OnChartTypeChanged(this, new ChartTypeChangeEventArgs() { chartType = _chartType });
            }
        }

        public CS.Util.PeriodType PeriodType
        {
            get
            {
                return _periodType;
            }
            set
            {
                _periodType = value;
                foreach (Telerik.Windows.Controls.RadMenuItem rmi in rimTimelineMenus.Items)
                {
                    if (rmi.Tag.ToString() == value.ToString().Substring(2))
                        rmi.IsChecked = true;
                    else
                        rmi.IsChecked = false;
                }
                //TODO: 当换时间的时候，应该重新获取数据，绑定数据源。
                GetDataFromService();
                if (OnPeriodTypeChanged != null)
                    OnPeriodTypeChanged(this, new PeriodTypeChangeEventArgs() { periodType = _periodType });
            }
        }

        public bool IsShowVolume
        {
            //成交量虽要重新做。
            get
            {
                return rcVolume.Visibility == Visibility.Visible;
            }
            set
            {
                if (value)
                {
                    rcVolume.Visibility = Visibility.Visible;
                }
                else
                {
                    rcVolume.Visibility = Visibility.Collapsed;
                }
            }
        }

        public bool IsIndicatorEnabled
        {
            get { return _isIndicatorEnabled; }
            set {
                _isIndicatorEnabled = value;
                rcProduct.IndicatorEnabled = value;
                rcVolume.IndicatorEnabled = value;
            }
        }

        public string ProductName
        {
            get
            {
                return _productName;
            }
        }

        public ChartTheme FXVChartTheme
        {
            get { return _chartTheme; }
            set
            {
                _chartTheme = value;
                ApplyTheme(_chartTheme);
            }
        }

        private void ApplyTheme(ChartTheme ct)
        {
            if (ct == null)
                throw new Exception("chart theme can not be null");
            rcProduct.PlotArea.Background = new SolidColorBrush(ct.BackgroundColor.Color);
            rcProduct.PlotArea.Foreground = new SolidColorBrush(ct.ForegroundColor.Color);
            // grid
            rcProduct.AxesX[0].Grids[0].LineColor = new SolidColorBrush(ct.GridColor.Color);
            rcProduct.AxesY[0].Grids[0].LineColor = new SolidColorBrush(ct.GridColor.Color);
            //
            rcProduct.Series[0].PriceUpColor = new SolidColorBrush(ct.BarStrokeColor.Color);
            //
            rcProduct.Series[0].PriceDownColor = new SolidColorBrush(ct.BarFillColor.Color);

            // volume
            
        }
        #endregion

        #region Context Menu Click Events
        //保存图表为图片
        private void rmiSaveToImg_Click(object sender, Telerik.Windows.RadRoutedEventArgs e)
        {
            SaveToImage();
        }

        // 保存图表数据
        private void rmiSaveData_Click(object sender, Telerik.Windows.RadRoutedEventArgs e)
        {
            SaveData();
        }

        private void rmiChartProperty_Click(object sender, Telerik.Windows.RadRoutedEventArgs e)
        {
            ChartPropertySetting();
        }

        // 刷新
        private void rimRefresh_Click(object sender, Telerik.Windows.RadRoutedEventArgs e)
        {
            rcProduct.Export();

        }

        // 时段变化
        private void TimeLineChange_Click(object sender, Telerik.Windows.RadRoutedEventArgs e)
        {
            this.PeriodType = Constants.GetPeroidTypeByString(((Telerik.Windows.Controls.RadMenuItem)sender).Tag.ToString());
            // 更新主界面
            MainPage mp = App.Current.RootVisual as MainPage;
            if (mp != null)
                mp.UpdateMainPageUI(this);
        }

        private void rimTimelineMenus_SubmenuClosed(object sender, Telerik.Windows.RadRoutedEventArgs e)
        {
            foreach (Telerik.Windows.Controls.RadMenuItem rmi in rimTimelineMenus.Items)
            {
                if (rmi.Tag.ToString() == this.PeriodType.ToString().Substring(2))
                    rmi.IsChecked = true;
                else
                    rmi.IsChecked = false;
            }
        }

        private void rimIndicator_Click(object sender, Telerik.Windows.RadRoutedEventArgs e)
        {
            IsIndicatorEnabled = !IsIndicatorEnabled;
        }
        #endregion
    }
}
